//------------------------------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.h"


#define DISABLE_SEND_ISR 	UCSRB &= ~_BV(UDRIE);	// Disable USART_UDRE interrupts.
#define ENABLE_SEND_ISR 	UCSRB |=  _BV(UDRIE);	// Enable USART_UDRE interrupts.


AVRX_DECL_FIFO(RxBuf, RX_BUFSZ);
AVRX_DECL_FIFO(TxBuf, TX_BUFSZ);

void InitUART(uint16_t ubrr)
{

	UBRRL = ubrr;
	UBRRH = (uint8_t)(ubrr>>8);
	UCSRA = (1<<U2X);
	UCSRB = ((1<<TXEN) | (1<<RXEN) | (1<<RXCIE));
	UCSRC = ((1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0));

	AVRX_INIT_FIFO(RxBuf);
	AVRX_INIT_FIFO(TxBuf);
    
}


int UARTBuffEmpty( void )
{
	int retc;
	
	if(AvrXPeekFifo(RxBuf) == FIFO_ERR)
        retc = TRUE;
	else
		retc = FALSE;

	return retc;
}

int put_c(char c, FILE *stream)	// Non blocking output
{
	int retc;
	retc = AvrXPutFifo(TxBuf, c);
	ENABLE_SEND_ISR;
	return retc;
}

int put_char(char c, FILE *stream)	// Blocking output
{
	AvrXWaitPutFifo(TxBuf, c);
	ENABLE_SEND_ISR;
	return 0;
}

int get_c(FILE *stream)	// Non blocking, return status outside of char range
{
	int retc = AvrXPullFifo(RxBuf);
	return retc;
}

int get_char(FILE *stream)	// Blocks waiting for something
{
	return AvrXWaitPullFifo(RxBuf);
}

FILE serial = FDEV_SETUP_STREAM(put_char,
								get_c,
								_FDEV_SETUP_RW);

// We don't care if the buffer is full.  Just signal we got one.
// The task may attempt one extra time to get data out of an empyt
// buffer (getc(), but so what.  Eventually it will block waiting
// for another character to be received.


// UART Receive Complete Interrupt Handler
AVRX_SIGINT( USART_RXC_vect )
{
    IntProlog();
    DISABLE_SEND_ISR;	// Disable Rx interrupt
    //sei();					// Allow other interrupt activity to occur
	AvrXPutFifo(RxBuf, UDR);// This resets the Rx Interrupt
	
	ENABLE_SEND_ISR;	// Re-enable.
	Epilog();
}


// USART Data Register Empty  Interrupt Handler
AVRX_SIGINT( USART_UDRE_vect )
{
    IntProlog();
    DISABLE_SEND_ISR;			// Disable UDRE interrupt
    //sei();							// Allow other stuff to happen
	int c = AvrXPullFifo(TxBuf);	// Return -1 if empty (enables interrupts)
	if (c >= 0)						// Tricky tight code: only checking sign
	{
		UDR = c;
		ENABLE_SEND_ISR;
	}
	Epilog();
}


// UART Transmit Complete Interrupt Handler
AVRX_SIGINT( USART_TXC_vect )
{
	IntProlog();
    DISABLE_SEND_ISR;	

	ENABLE_SEND_ISR;
	Epilog();
}
